package de.dhbw.karlsruhe.picsim.model.io;

import de.dhbw.karlsruhe.picsim.model.cpu.Interrupt;
import de.dhbw.karlsruhe.picsim.model.cpu.InterruptFacade;
import de.dhbw.karlsruhe.picsim.model.cpu.ReadOnlyFile;
import de.dhbw.karlsruhe.picsim.util.Bits;
import org.jetbrains.annotations.NotNull;

/**
 * Created by IntelliJ IDEA.
 * User: goesen
 * Date: May 6, 2010
 * Time: 12:03:28 PM
 */
public final class ExternalInterrupts implements External.ExternalListener {
    private final InterruptFacade interruptFacade;
    private final ReadOnlyFile option;

    public ExternalInterrupts(final InterruptFacade interruptFacade, final ReadOnlyFile option) {
        this.interruptFacade = interruptFacade;
        this.option = option;
    }

    @Override
    public void handlePortAChange(@NotNull final Bits oldValue, @NotNull final Bits newValue) {
        //intressiert uns nicht
    }

    @Override
    public void handlePortBChange(@NotNull final Bits oldValue, @NotNull final Bits newValue) {
        checkPortBInterrupt(oldValue, newValue);
        checkRB0Interrupt(oldValue, newValue);
    }

    private void checkRB0Interrupt(final Bits oldValue, final Bits newValue) {
        final boolean rb0 = newValue.isSet(0);
        if (rb0 != oldValue.isSet(0)) {
            /*
            P.15
            INTEDG: Interrupt Edge Select bit
            1 = Interrupt on rising edge of RB0/INT pin
            0 = Interrupt on falling edge of RB0/INT pin
            bit 6:
            */
            final boolean interruptOnRising = getINTEDGFlag();
            if (interruptOnRising && rb0 || !interruptOnRising && !rb0) {
                interruptFacade.putInterrupt(Interrupt.RB_0);
            }
        }
    }

    private boolean getINTEDGFlag() {
        return option.getData().isSet(6);
    }

    private void checkPortBInterrupt(final Bits oldValue, final Bits newValue) {
        /*
        P.48
        An input change on PORTB<7:4> sets ﬂag bit RBIF
        (INTCON<0>). The interrupt can be enabled/disabled
        by setting/clearing enable bit RBIE (INTCON<3>)
        (Section 5.2).
        */

        for (int i = 4; i < 8; i++) {
            if (newValue.isSet(i) != oldValue.isSet(i)) {
                interruptFacade.putInterrupt(Interrupt.PortB);
                break;
            }
        }
    }

}
